/******************************************************************************
 * Copyright 2022 The Airos Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/
#include <string>

#include <gflags/gflags.h>
#include <glog/logging.h>
#include "config/config.h"
#include "components/fake_obu_service/fake_obu_service.h"
#include "net/udp/udp_impl.h"
#include "codec/fake_obu_rsu_codec/fake_obu_rsu_codec.h"

namespace air {
namespace net {

DEFINE_bool(net_use_fake_obu_asn, true, "");
DEFINE_int32(net_fake_obu_asn_type, 1, "");
DEFINE_bool(net_use_fake_obu_proto, true, "");

void FakeObuReceiver::OnInit() {
  net_ = air::net::UdpImpl::GetInstance();
  if (net_ == nullptr) {
      LOG(ERROR) << "init fake obu service failed";
      Stop();
  }
  switch (FLAGS_net_fake_obu_asn_type) {
    case 1:
      asn_type_ = EnAsnType::CASE_53_2020;
      break;
    case 2:
      asn_type_ = EnAsnType::YDT_3709_2020;
      break;
    default:
      asn_type_ = EnAsnType::CASE_53_2020;
      break;
  }
  send_list_ = air::config::Config::GetInstance()
    ->GetSendList(GetWorkerName());
  LOG(INFO)
    << "net_use_fake_obu_asn: "
    << FLAGS_net_use_fake_obu_asn;
  LOG(INFO)
    << "net_fake_obu_asn_type: "
    << FLAGS_net_fake_obu_asn_type;
  LOG(INFO)
    << "net_use_fake_obu_proto: "
    << FLAGS_net_use_fake_obu_proto;
  LOG(INFO) << GetWorkerName() << " send list:";
  for (int i = 0; i < send_list_.size(); ++i) {
    LOG(INFO) << send_list_[i];
  }
}

void FakeObuReceiver::Run() {
  std::string src;
  std::string data;
  if (-1 == net_->Recv(&src, &data)) {
      LOG(ERROR) << "fake obu service recv failed";
      return;
  }
  // decode asn msg
  uint8_t t;
  std::string asn_data;
  if (FLAGS_net_use_fake_obu_proto) {
    if (-1 == air::codec::FakeObuRsuCodec::Decode(
                  data,
                  &t,
                  &asn_data)) {
      LOG(WARNING) << "decode msg failed";
      return;
    }
  } else {
    LOG(INFO) << "using raw proto";
    asn_data = data;
  }
  std::string asnpb_data;
  if (FLAGS_net_use_fake_obu_asn) {
    auto res = message_frame_uper2pbstr_adapter(asn_data,
        &asnpb_data, asn_type_);
    if (res <= 0) {
      LOG(ERROR) << "convert asn to protobuf failed";
      return;
    }
  } else {
    LOG(INFO) << "using raw data";
    asnpb_data = asn_data;
  }
  for (int i = 0; i < send_list_.size(); ++i) {
    DLOG(INFO) << "send to " << send_list_[i];
    auto msg = std::make_shared<air::link::Msg>();
    msg->SetData(asnpb_data);
    SendMsg(send_list_[i], msg);
  }
  DispatchMsg();
}

void FakeObuReceiver::OnExit() {}

void FakeObuSender::OnInit() {
  net_ = air::net::UdpImpl::GetInstance();
  if (net_ == nullptr) {
      LOG(ERROR) << "init fake obu service failed";
      Stop();
  }
  switch (FLAGS_net_fake_obu_asn_type) {
  case 1:
    asn_type_ = EnAsnType::CASE_53_2020;
    break;
  case 2:
    asn_type_ = EnAsnType::YDT_3709_2020;
    break;
  default:
    asn_type_ = EnAsnType::CASE_53_2020;
    break;
  }
}

void FakeObuSender::Run() {
  DispatchAndWaitMsg();
  while (RecvMsgListSize() > 0) {
    const auto& msg = GetRecvMsg();
    auto data = msg->GetData();
    std::string asn_data;
    if (FLAGS_net_use_fake_obu_asn) {
      auto res = message_frame_pbstr2uper_adapter(data,
          &asn_data, asn_type_);
      if (res <= 0) {
        LOG(ERROR) << "convert asn to protobuf failed";
        continue;
      }
    } else {
      LOG(INFO) << "using raw data";
      asn_data = data;
    }
    std::string pack_msg;
    if (FLAGS_net_use_fake_obu_proto) {
      pack_msg = ::air::codec::FakeObuRsuCodec::Encode(
        uint8_t(air::codec::FakeObuRsuCodec::MsgType::kBsm),
        asn_data);
      if (pack_msg.empty()) {
        LOG(WARNING) << "encode msg failed";
        continue;
      }
    } else {
      LOG(INFO) << "using raw proto";
      pack_msg = asn_data;
    }
    if (-1 == net_->Send("", pack_msg)) {
        LOG(ERROR) << "fake obu service send failed";
    }
  }
}

void FakeObuSender::OnExit() {}

}  // namespace net
}  // namespace air
